package com.jiangjun.fetch.filter;

import java.io.IOException;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.GzipDecompressingEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jiangjun.fetch.common.AttributeChain;
import com.jiangjun.fetch.common.WebContext;
import com.jiangjun.fetch.util.DateUtil;
import com.jiangjun.fetch.util.UrlUtil;

public class HttpClientFilter extends Filter {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Override
	public String doProcess(final WebContext ctx) throws Exception {
		// TODO Auto-generated method stub
		String charset = "";
		String resource = "";
		String url = ctx.getUrl();
		if (!url.toLowerCase().startsWith("http"))
			url = "http://" + url;
		if (url.indexOf("http://dcd.10086.cn") > -1)
			url = url + "&bf=0";
		url = UrlUtil.urlEscape(url);
		logger.info("url:" + url);
		HttpParams params = new BasicHttpParams();
		params.setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,
				false);
		// params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET,
		// HTTP.UTF_8);
		params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
				HttpVersion.HTTP_1_1);
		params.setParameter(ClientPNames.COOKIE_POLICY,
				CookiePolicy.BROWSER_COMPATIBILITY);
		params.setParameter(ClientPNames.HANDLE_REDIRECTS, true);
		params.setParameter(ClientPNames.HANDLE_AUTHENTICATION, true);
		params.setParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, true);
		params.setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
		params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);
		params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 60000);
		HttpGet httpGet = new HttpGet(url.trim());
		httpGet.setParams(params);
		httpGet.setHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/15.0");
		httpGet.setHeader("Accept-Encoding", "gzip");
		httpGet.setHeader("Accept",
				"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		httpGet.setHeader("Accept-Language",
				"zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");

		/**
		 * 判断是否有更新
		 */
		if (null != ctx.getIsRssXml() && "1".equals(ctx.getIsRssXml())
				&& null != ctx.getLastUpdateTime()
				&& !"".equals(ctx.getLastUpdateTime())) {
			httpGet.setHeader("If-Modified-Since", DateUtil.getGMTdate(Long
					.parseLong(ctx.getLastUpdateTime())));
		}
		DefaultHttpClient httpClient = new DefaultHttpClient(params);

		httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
			@Override
			public void process(HttpResponse response, HttpContext context)
					throws HttpException, IOException {
				System.out.println(response.getStatusLine());
				HttpEntity entity = response.getEntity();
				if (entity == null) {
					return;
				}
				Header ceheader = entity.getContentEncoding();
				if (ceheader != null) {
					HeaderElement[] codecs = ceheader.getElements();
					for (int i = 0; i < codecs.length; i++) {
						if (codecs[i].getName().equalsIgnoreCase("gzip")) {
							response.setEntity(new GzipDecompressingEntity(
									entity));
							return;
						}
					}
				}
			}
		});

		try {
			HttpResponse response = httpClient.execute(httpGet);
			if (response.getStatusLine().getStatusCode() == 200) {
				HttpEntity entity = response.getEntity();
				HeaderIterator hi = response.headerIterator();
				while (hi.hasNext()) {
					Header header = hi.nextHeader();
					if (header.getName().equalsIgnoreCase("Last-Modified")) {
						ctx.setLastUpdateTime(DateUtil.getMills(header
								.getValue()) + "");
						break;
					}
				}
				Header contentEncodingHeader = entity.getContentEncoding();
				if (contentEncodingHeader != null) {
					for (HeaderElement element : contentEncodingHeader
							.getElements()) {
						if (element.getName().equalsIgnoreCase("gzip")) {
							response.setEntity(new GzipDecompressingEntity(
									response.getEntity()));
							entity = response.getEntity();
						}
					}
				}
				Header contentType = entity.getContentType();
				if (contentType != null) {
					String type = contentType.getValue().toLowerCase().trim();
					charset = parseContentType(type, ctx);
					/**
					 * http://gaokao.eol.cn/zui_xin_dong_tai_2933/20121202/
					 * t20121202_875369.shtml
					 * 这个网页的Content-Type:text/html;charset=None "None"
					 * 当charset=None时，则赋值charset="gb2312"
					 */
					if (charset.toLowerCase().equals("none")) {
						charset = "gb2312";
					}
					if (type.equalsIgnoreCase("text/xml"))
						charset = "gb2312";
				}
				if (charset.equalsIgnoreCase("gb2312")
						|| charset.equalsIgnoreCase("gbk")) {
					charset = "GB18030";
				}
				if (!"".equals(charset)) {
					if (charset.equalsIgnoreCase("GB18030")) {
						byte[] b = EntityUtils.toByteArray(entity);
						resource = new String(b, "GB18030");
					} else {
						resource = EntityUtils.toString(entity, charset);
					}
				} else {
					resource = EntityUtils.toString(entity, "ISO-8859-1");
					charset = getEncodeFormMeta(resource);
					if ("".equals(charset))
						charset = "utf-8";
					if (charset.equalsIgnoreCase("gb2312")
							|| charset.equalsIgnoreCase("gbk")) {
						charset = "GB18030";
					}
					resource = new String(resource.getBytes("ISO-8859-1"),
							charset);
				}
				// 修复空格变问号的问题（空格在转码之后变成？）
				resource = resource.replaceAll("&nbsp;", " ");
				resource = resource.replaceAll("ignore_js_op", "div");
				resource = resource.trim().replaceFirst("^([\\W]+)<", "<");
				// if (ctx.getUrl().indexOf("m.pp.cn") > -1) {
				// if (resource.indexOf("<form") > -1) {
				// int i = resource.indexOf("<form");
				// resource = resource.substring(0, i) + "</body></html>";
				// }
				// }
				ctx.setCharset(charset);
				ctx.setContent(resource);
			} else {
				return null;
			}
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			httpClient.getConnectionManager().shutdown();
		}
		if (null != ctx.getIsRssXml() && ctx.getIsRssXml().equals("1")) {
			return AttributeChain.PARSERSSXML_FILTER;
		}
		return AttributeChain.HTMLDOCUMENT_FILTER;
	}

	/**
	 * 解析contentType 获得字符集 TODO 添加方法注释
	 * 
	 * @param contentType
	 * @return String
	 */
	public String parseContentType(String contentType, WebContext ctx) {
		if (contentType.toLowerCase().indexOf("charset") > -1) {
			String[] cs;
			contentType = contentType.replace(" ", "");// 有的网页的contentType参数里有空格，影响解析
			if (contentType.indexOf(";;") > -1) {
				cs = contentType.split(";;");
			} else {
				cs = contentType.split(";");
			}
			if (cs.length < 2 && contentType.indexOf("charset") > -1) {
				return contentType.split("=")[1].trim();
			}
			String[] ch = cs[1].split("=");
			if (ch[1].split(",").length > 1) {
				return ch[1].split(",")[0];
			}
			return ch[1];
		} else {
			String url = ctx.getUrl();
			if (url.indexOf("baidu") > -1) {
				if (url.indexOf("tieba.baidu") > -1) {
					return "gbk";
				} else {
					return "gb2312";
				}
			}
			return "";
		}
	}

	/**
	 * 获得meta里的字符集
	 */
	public String getEncodeFormMeta(String con) {
		if (null == con || "".equals(con)) {
			return "";
		}
		int f = 0;
		int l = 0;
		if (con.toLowerCase().indexOf("content-type") > -1) {
			if (con.toLowerCase().indexOf("<meta http-equiv=\"content-type\"") > -1)
				f = con.toLowerCase().indexOf(
						"<meta http-equiv=\"content-type\"");

			l = con.indexOf(">", f);
			String words = con.substring(f, l + 1);
			if (words.indexOf("content") > -1) {
				String content = "";
				if (words.indexOf("/>") > -1) {
					content = words.substring(words.indexOf("content"),
							words.indexOf("/>"));
				} else {
					content = words.substring(words.indexOf("content"),
							words.indexOf(">"));
				}

				try {
					if (content.toLowerCase().indexOf("charset") > -1) {
						String[] ss = content.split(";");
						String code = (ss[1].split("="))[1];
						code = code.replace("\"", "");
						return code.trim();
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					if (content.indexOf("charset=\"") > -1) {
						int i = content.indexOf("charset=\"");
						int j = content.indexOf("\"", i + 1);
						int k = content.indexOf("\"", j + 1);
						String s = content.substring(j + 1, k);
						return s.trim();
					}
				}
			}
			if (con.toLowerCase().indexOf("<meta charset=\"gb2312\"") > -1) {
				return "gb2312";
			}
			if (con.toLowerCase().indexOf("charset") > -1) {
				if (con.toLowerCase().indexOf("charset=gb2312") > -1) {
					return "gb2312";
				} else if (con.toLowerCase().indexOf("charset=utf-8") > -1) {
					return "utf-8";
				} else if (con.toLowerCase().indexOf("charset=gbk") > -1) {
					return "gbk";
				}
				int i = con.toLowerCase().indexOf("charset=\"");
				int j = con.toLowerCase().indexOf("\"", i + 1);
				int k = con.toLowerCase().indexOf("\"", j + 1);
				String s = con.toLowerCase().substring(j + 1, k);
				return s.trim();
			}
		} else if (con.toLowerCase().indexOf("<meta charset=") > -1) {
			int i = con.toLowerCase().indexOf("<meta charset=");
			int j = con.toLowerCase().indexOf(">", i);
			con = con.toLowerCase().substring(i, j + 1);
			if (con.indexOf("utf-8") > -1) {
				return "utf-8";
			} else if (con.indexOf("gb2312") > -1) {
				return "gb2312";
			} else if (con.indexOf("gbk") > -1) {
				return "gbk";
			}

		}
		return "";
	}
}
